package com.basker.pisces.core.meta.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.util.CollectionUtils;

import com.basker.pisces.common.LazyProvider;
import com.basker.pisces.core.meta.ICollectionField;
import com.basker.pisces.core.meta.IDataField;
import com.basker.pisces.core.meta.IDataObjectMeta;
import com.basker.pisces.core.meta.IField;

public class DataObjectMetaUtils {

    /**
     * 根据前缀过滤source
     *
     * @param prefix    前綴
     * @param source    过滤源
     * @param cutPrefix 返回值是否需要去掉前缀
     * @return
     */
    public static List<String> filterByPrefix(String prefix, Collection<String> source, boolean cutPrefix) {
        source = source.stream().filter(v -> v != null).map(v -> v.trim()).collect(Collectors.toList());

        if (prefix == null || prefix.equals("")) {
            return new ArrayList<>(source);
        } else {
            final String prefix2use = !prefix.endsWith(".") ? (prefix + ".") : prefix;

            Stream<String> stream = source.stream().filter(m -> m.startsWith(prefix2use));

            if (cutPrefix) {
                stream = stream.map(m -> m.substring(prefix2use.length()));
            }

            return stream.collect(Collectors.toList());
        }
    }

    /**
     * 获取元数据的主键、代码和名称字段
     *
     * @param objectMeta
     * @return
     */
    public static List<String> getIdCodeNameFields(IDataObjectMeta objectMeta) {
        LazyProvider<List<String>> provider = new LazyProvider<>(() -> new ArrayList<>(3));

        IDataField field = objectMeta.getPkField();
        if (field != null) {
            provider.get().add(field.getName());
        }

        field = objectMeta.getCodeField();
        if (field != null) {
            provider.get().add(field.getName());
        }

        field = objectMeta.getNameField();
        if (field != null) {
            provider.get().add(field.getName());
        }

        return provider.isPresent() ? provider.get() : Collections.emptyList();
    }

    /**
     * 对于给定的fields参数，获取对于objectMeta的合法字段
     *
     * @param objectMeta
     * @param fields
     * @param isRefMeta  是否是引用元数据
     * @return
     */
    public static List<String> getValidFields(IDataObjectMeta objectMeta, Collection<String> fields,
                                              boolean isRefMeta) {
        Double s = fields.size() * 1.2;
        List<String> validFields = new ArrayList<>(s.intValue());

        List<String> currentFields = filterByPrefix(null, fields, true);
        fillValidFields(validFields, null, objectMeta, currentFields, isRefMeta);

        Collections.sort(validFields);

        return validFields;
    }

    /**
     * 根据字段名从objectMeta查询字段，对于子对象的字段，可以通过在 "a.b"这样方式查找
     *
     * @param objectMeta
     * @param fieldName
     * @return
     */
    public static IField tryFindField(IDataObjectMeta objectMeta, String fieldName) {
        String[] names = fieldName.split("//.");
        String lastName = names[names.length - 1];
        IDataObjectMeta meta2Use = objectMeta;

        for (String name : names) {
            IField field = meta2Use.getField(name);

            if (name.equals(lastName)) {
                return field;
            }

            if (field instanceof ICollectionField) {
                meta2Use = ((ICollectionField) field).getItemObjectMeta();
            }
        }

        return null;
    }

    private static void fillValidFields(List<String> validFields, String currentMetaHostField,
                                        IDataObjectMeta currentObjectMeta, List<String> currentFields, boolean isRefMeta) {
        List<String> fieldsToAdd = new ArrayList<>(currentFields.size() + 2);// 2是为了给id和时间戳字段预留

        Consumer<String> addFieldName = val -> {
            String fieldName = currentMetaHostField != null ? currentMetaHostField + "." + val : val;
            fieldsToAdd.add(fieldName);
        };

        // 对于当前契约的成员，将A.1,A.2,B.1,B.2的成员，转换成A,B
        Set<String> fieldSet = currentFields.stream().map(name -> name.split("\\.")[0]).collect(Collectors.toSet());

        // 遍历名称集合，将合法的字段添加到membersToAdd
        for (String name : fieldSet) {
            IField field = currentObjectMeta.getField(name);
            if (field == null) {
                continue;
            }

            addFieldName.accept(name);
        }

        if (!CollectionUtils.isEmpty(fieldsToAdd)) {
            // 检查 是否包含主键
            String pkFieldName = currentObjectMeta.getPkField().getName();
            if (!fieldSet.contains(pkFieldName)) {
                addFieldName.accept(pkFieldName);
            }

            if (!isRefMeta) {
                // 检查是否包含时间戳
                IDataField timestampField = currentObjectMeta.getTimestampField();
                if (timestampField != null && !fieldSet.contains(timestampField.getName())) {
                    addFieldName.accept(timestampField.getName());
                }
            }

            validFields.addAll(fieldsToAdd);
        } else {
            // 没有合法的字段，不再遍历子对象
            return;
        }

        for (ICollectionField collField : currentObjectMeta.getCollectionFields()) {
            String collFieldName = collField.getName();
            if (!fieldSet.contains(collFieldName)) {
                continue;
            }

            List<String> collMetaFields = filterByPrefix(collFieldName, currentFields, true);
            if (CollectionUtils.isEmpty(collMetaFields)) {
                continue;
            }

            fillValidFields(validFields, collFieldName, collField.getItemObjectMeta(), collMetaFields, isRefMeta);
        }

    }

}
